package com.jing.yuntuku.utils;

import com.aliyun.oss.ClientException;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.model.OSSObject;
import com.aliyun.oss.model.ObjectMetadata;
import com.aliyun.oss.model.PutObjectRequest;
import com.aliyun.oss.model.PutObjectResult;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.io.*;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

@Data
@Slf4j
@Component
public class AliOssUtil {
    @Value("${feven.alioss.endpoint}")
    private String endpoint;
    @Value("${feven.alioss.access-key-id}")
    private String accessKeyId;
    @Value("${feven.alioss.access-key-secret}")
    private String accessKeySecret;
    @Value("${feven.alioss.bucket-name}")
    private String bucketName;

    private OSS ossClient;


    /**
     * 文件上传
     *
     * @param bytes
     * @param objectName
     * @return
     */
    public String upload(byte[] bytes, String objectName) {

        // 创建OSSClient实例。
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);

        try {
            // 创建PutObject请求。
            ossClient.putObject(bucketName, objectName, new ByteArrayInputStream(bytes));
        } catch (OSSException oe) {
            System.out.println("Caught an OSSException, which means your request made it to OSS, "
                    + "but was rejected with an error response for some reason.");
            System.out.println("Error Message:" + oe.getErrorMessage());
            System.out.println("Error Code:" + oe.getErrorCode());
            System.out.println("Request ID:" + oe.getRequestId());
            System.out.println("Host ID:" + oe.getHostId());
        } catch (ClientException ce) {
            System.out.println("Caught an ClientException, which means the client encountered "
                    + "a serious internal problem while trying to communicate with OSS, "
                    + "such as not being able to access the network.");
            System.out.println("Error Message:" + ce.getMessage());
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }

        //文件访问路径规则 https://BucketName.Endpoint/ObjectName
        StringBuilder stringBuilder = new StringBuilder("https://");
        stringBuilder
                .append(bucketName)
                .append(".")
                .append(endpoint)
                .append("/")
                .append(objectName);

        log.info("文件上传到:{}", stringBuilder);

        return stringBuilder.toString();
    }

    public PutObjectResult putPictureObject(String key, File file) {
        // 创建上传请求
        PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, key, file);

        // 创建元数据，用于设置图片处理参数
        ObjectMetadata metadata = new ObjectMetadata();

        // 设置需要返回的图片信息，这里示例获取宽、高、格式信息
        // 阿里云通过x-oss-process参数指定图片处理行为
        // 详细参数参考：https://help.aliyun.com/document_detail/44688.html
        Map<String, String> userMetadata = new HashMap<>();
        // 这里设置用户自定义元数据，实际图片信息需要通过处理URL获取
        userMetadata.put("x-oss-process", "image/info");
        metadata.setUserMetadata(userMetadata);

        putObjectRequest.setMetadata(metadata);

        // 执行上传
        PutObjectResult result = ossClient.putObject(putObjectRequest);

        return result;
    }

    /**
     * 从OSS下载文件，返回字节数组
     *
     * @param objectName OSS中的文件名
     * @return 文件的字节数组
     * @throws IOException 当IO操作失败时抛出
     */
    public byte[] download(String objectName) throws IOException {
        // 创建OSSClient实例
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
        OSSObject ossObject;
        InputStream inputStream = null;
        ByteArrayOutputStream outputStream = null;

        try {
            // 获取OSS中的文件对象
            ossObject = ossClient.getObject(bucketName, objectName);
            inputStream = ossObject.getObjectContent();
            outputStream = new ByteArrayOutputStream();

            // 读取文件内容到字节数组
            byte[] buffer = new byte[1024];
            int len;
            while ((len = inputStream.read(buffer)) != -1) {
                outputStream.write(buffer, 0, len);
            }

            log.info("文件下载成功: {}", objectName);
            return outputStream.toByteArray();
        } catch (OSSException oe) {
            log.error("OSSException occurred while downloading file: {}", objectName, oe);
            throw new IOException("Failed to download file from OSS", oe);
        } catch (ClientException ce) {
            log.error("ClientException occurred while downloading file: {}", objectName, ce);
            throw new IOException("Failed to connect to OSS", ce);
        } finally {
            // 关闭流资源
            if (outputStream != null) {
                try {
                    outputStream.close();
                } catch (IOException e) {
                    log.error("Error closing output stream", e);
                }
            }
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    log.error("Error closing input stream", e);
                }
            }
            // 关闭OSSClient
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
    }

    /**
     * 生成带签名的下载URL
     *
     * @param objectName    OSS中的文件名
     * @param expireSeconds 有效期(秒)
     * @return 带签名的下载URL
     */
    public String generateDownloadUrl(String objectName, int expireSeconds) {
        // 创建OSSClient实例
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);

        try {
            // 计算URL过期时间
            Date expiration = new Date(System.currentTimeMillis() + expireSeconds * 1000L);

            // 生成签名URL
            String url = ossClient.generatePresignedUrl(bucketName, objectName, expiration).toString();
            log.info("生成下载URL成功: {}", url);
            return url;
        } catch (OSSException oe) {
            log.error("OSSException occurred while generating download URL: {}", objectName, oe);
            throw new RuntimeException("Failed to generate download URL", oe);
        } catch (ClientException ce) {
            log.error("ClientException occurred while generating download URL: {}", objectName, ce);
            throw new RuntimeException("Failed to generate download URL", ce);
        } finally {
            // 关闭OSSClient
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
    }
}
